#!/usr/bin/env python
# encoding: utf-8
# Date: 2017/5/13 上午10:39
# file: crane.py
# Email: wangjian2254@icloud.com
# Author: 王健
import uuid


class Billet(object):
    """
    钢坯
    """

    STATUS_NONE = 0
    STATUS_UP = 1
    STATUS_DOWN = 2
    STATUS_MOVE = 3
    STATUS_OUT = 4

    Billet_Status_Chiose = (
        (STATUS_NONE, u'未入系统'),
        (STATUS_UP, u'行车上'),
        (STATUS_DOWN, u'库位中'),
        (STATUS_MOVE, u'小车中'),
        (STATUS_OUT, u'移出库区'),
    )

    def __init__(self, bm, kind, outer_radius, weight, inner_radius=200):
        # 编码
        self.bm = bm
        # 钢坯类型
        self.kind = kind

        # 内半径
        self.inner_radius = inner_radius

        # 外半径
        self.outer_radius = outer_radius

        # 重量
        self.weight = weight

        self.status = Billet.STATUS_NONE

        self.position = (-1, -1, -1)

        self.aim_position = (-1, -1, -1)

        self.position_list = []

        self.area = None

        self.aim_area = None

    def set_area(self, area):
        """
        设置所在库区
        :param area: 
        :return: 
        """
        self.area = area

    def set_aim_area(self, aim_area):
        """
        设置目标库区
        :param aim_area: 
        :return: 
        """
        self.aim_area = aim_area

    def set_position(self, area, position):
        """
        设置存储库区和位置
        :param area: 
        :param position: 
        :return: 
        """
        self.area = area
        self.position = position

    def set_aim_position(self, aim_area, aim_position):
        """
        设置目标库区和位置
        :param aim_area: 
        :param aim_position: 
        :return: 
        """
        self.aim_area = aim_area
        self.aim_position = aim_position

    def is_same_area(self):
        """
        设置
        :return: 
        """
        if self.area and self.aim_area and self.area.number == self.aim_area.number:
            return True
        else:
            return False


class StoragePosition(object):
    """
    库存卡座
    """

    def __init__(self, area, bm, x1, x2, y, width):
        self.area = area
        self.bm = bm
        self.x1 = x1
        self.x2 = x2
        self.y = y
        self.width = width

        self.y1 = y - width / 2
        self.y2 = y + width / 2

    def pzjc(self, position):

        x1 = position.x1
        x2 = position.x2
        y1 = position.y1
        y2 = position.y2

        if self.x1 < x1 < self.x2 and self.y1 < y1 < self.y2:
            return True
        elif self.x1 < x2 < self.x2 and self.y1 < y1 < self.y2:
            return True
        elif self.x1 < x1 < self.x2 and self.y1 < y2 < self.y2:
            return True
        elif self.x1 < x2 < self.x2 and self.y1 < y2 < self.y2:
            return True

        return False

    @staticmethod
    def make_position(pos):
        """
        计算出坐标列表
        :param pos:
        :return:
        """
        if isinstance(pos, (str, unicode)):
            return pos.split(',')
        else:
            return pos

    def computer_position(self, ):
        """
        根据规则计算,卷位中心点物理坐标
        :return:
        """


class StorageArea(object):
    """
    库区
    """

    # 原料
    YUANLIAO = 'yuanliao'

    # 中间环节
    ZHONGJIAN = 'zhongjian'

    # 检测环节
    JIANCHA = 'jiancha'

    # 成品区
    CHENGPIN = 'chengpin'

    def __init__(self, number, name, width, height, layer):
        self.number = number
        self.name = name
        # 单位为毫米
        self.width = width
        self.height = height

        self.center_y = height / 3.0 * 2

        # 层数
        self.layer = layer

        # 本地天车
        self.local_cranes = []

        # 可以沟通的外部区域
        self.external_area = []

        # 与外部区域沟通的对应点位
        self.external_area_position = {}

        # 卡座列表
        self.position_list = []

        self.position_arr = []

        # 出库位置
        self.external_position = {}

    def set_center_y(self, y):
        """
        天车工作交界线
        :param y:
        :return:
        """
        self.center_y = y


    def append_position(self, x, y, position):
        """
        向库区里添加卡座
        :param position:
        :return:
        """

        # 加入卡座前, 校验一下 卡座有没有 重叠
        is_ok = True
        for p in self.position_list:
            if p.pzjc(position):
                print p.bm
                is_ok = False
        # for a_p in self.external_area_position.values():
        #     for p in a_p:
        #         if p.pzjc(position):
        #             print p.bm
        #             is_ok = False
        if is_ok:
            self.position_list.append(position)
            if len(self.position_arr) - 1 < y:
                for i in range(y - len(self.position_arr) + 1):
                    self.position_arr.append([])
            if len(self.position_arr[y]) < x:
                for i in range(x - len(self.position_arr[y])):
                    self.position_arr[y].append(None)
            self.position_arr[y].append(position)

    def append_cranes(self, cranes):
        """
        添加天车
        :param cranes:
        :return:
        """

        self.local_cranes.append(cranes)

    def append_area(self, area, position_list):
        """
        设置与本库区关联的库区
        :param area:
        :return:
        """
        self.external_area.append(area)
        self.external_area_position[area.number] = position_list

    def append_external(self, flag, position_list):
        """
        设置出库的位置列表
        :param flag:
        :param position_list:
        :return:
        """
        self.external_position[flag] = position_list


class ActionCommand(object):
    """
    行车命令
    """
    # 未分解
    STATUS_UN = -1

    # 等待
    STATUS_NONE = 0

    # 进行
    STATUS_DOING = 1

    # 暂停
    STATUS_STOP = 2

    # 完成
    STATUS_FINISH = 3

    # 取消
    STATUS_CANCEL = 4

    # 等待主命令完成
    STATUS_CHECK = 5

    # 部分完成,等待自命令完成
    STATUS_PART = 6

    # 失败
    STATUS_FAIL = 7

    def __init__(self, no=None, action=None, args=None, is_sub=False, parent=None):
        self.pk = str(uuid.uuid4())
        self.no = no
        self.action = action
        self.args = args
        self.is_sub = is_sub
        self.parent = parent
        if self.parent:
            self.status = ActionCommand.STATUS_CHECK
        else:
            self.status = ActionCommand.STATUS_NONE

        self.crane = None

        # 子命令
        self.sub_action_command = []

        if self.parent:
            self.parent.append_sub_action_command(self)

    def append_sub_action_command(self, sub_action):
        """
        追加子命令
        :param sub_action:
        :return:
        """
        self.sub_action_command.append(sub_action)

    def set_crane(self, crane):
        """
        设置执行的天车
        :param crane:
        :return:
        """
        self.crane = crane

    def set_action(self, action, args):
        """
        设置命令模式
        :param action:
        :return:
        """
        if action not in [Crane.ACTION_OPEN, Crane.ACTION_CLOSE, Crane.ACTION_MOVE, Crane.ACTION_STOP]:
            return u'无法识别的命令'
        self.action = action
        self.args = args

    def set_status(self, status):
        """
        设置
        :param status:
        :return:
        """
        self.status = status

    def is_closed(self):
        return self.status == ActionCommand.STATUS_FINISH or self.status == ActionCommand.STATUS_CANCEL

    def compute_time(self, crane=None):
        if self.action in [Crane.ACTION_OPEN, Crane.ACTION_CLOSE]:
            return 3
        elif self.action == Crane.ACTION_MOVE:
            if not crane:
                return 100
            t = 0
            if crane.speed:
                pass
            return 10
        elif self.action == Crane.ACTION_STOP:
            return 4


class Crane(object):
    """
    天车
    """
    # 夹子开口
    ACTION_OPEN = "open"
    # 夹子闭合
    ACTION_CLOSE = "close"
    # move 移动
    ACTION_MOVE = "move"
    # 移动小车
    ACTION_MOVE_CAR = "move_car"
    # 移动钩子
    ACTION_MOVE_G = "move_g"
    # 降落钩子至失去重量
    ACTION_DOWN_G = "down_g"
    # 停止、等候命令
    ACTION_STOP = "stop"

    def __init__(self, number, area):
        self.number = number
        self.area = area

        # 大车 速度和 加速减速的补偿时间 m/s
        self.speed_list = [1.0, 1.2, 1.4, 1.6, 2.0]

        # 小车 速度和 加速减速的补偿时间
        self.car_speed_list = [0.50, 0.55, 0.60, 0.70, 0.80]
        # 主钩子 速度和 加速减速的补偿时间
        self.gou_speed_list = [0.1, 0.2, 0.3]

        # 当前大车速度
        self.speed = 0
        self.car_speed = 0
        self.gou_speed = 0

        self.x = 0
        self.y = 0
        self.z = 0
        # 夹子开口度
        self.o = 0

        # 重量
        self.weight = 0

        self.a_x = 0
        self.a_y = 0
        self.a_z = 0

        self.billet = None

        self.action_list = []

    def set_position(self, x, y, z):
        """
        设置当前天车的位置
        :param x:
        :param y:
        :param z:
        :return:
        """

        self.x = x
        self.y = y
        self.z = z

    def set_aim_position(self, x, y, z):
        """
        设置天车的目标位置
        :param x:
        :param y:
        :param z:
        :return:
        """

        self.a_x = x
        self.a_y = y
        self.a_z = z

    def set_billet(self, billet):
        """
        设置天车携带的钢卷
        :param billet:
        :return:
        """
        self.billet = billet

    def remove_billet(self):
        """
        移除钢卷
        :return:
        """
        billet = self.billet
        self.billet = None
        return billet

    def is_free(self):
        """
        天车是否空闲
        :return:
        """
        free = True
        for action in self.action_list:
            if not action.is_closed():
                free = False
        if free:
            return self.billet is None
        else:
            return free

    def add_actions(self, action):
        self.action_list.append(action)
